package gbench.appdemo.mall.erp.components;

import static gbench.common.tree.LittleTree.IRecord.REC;
import static gbench.common.tree.LittleTree.SQL.nsql;
import static gbench.common.tree.LittleTree.Term.FT;
import static java.time.LocalDateTime.now;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import gbench.common.tree.LittleTree.SQL;

/**
 * 
 * @author gbench
 *
 * @param <S>
 */
public interface IOrder<S> extends IContract{
    
    /**
     * 
     * @return
     */
    public Integer getId();

    /**
     * 
     * @param id
     * @return
     */
    public Integer setId(Integer id);

    /**
     * 产品名称
     * 
     * @return
     */
    public String getName();

    /**
     * 加入所有lineItems
     * 
     * @param lineItems
     */
    public void addAll(final List<ILineItem> lineItems);

    /**
     * 
     * @param <T>
     * @param ll
     * @return
     */
    public <T extends ILineItem> Integer setLineItems(final List<T> ll);

    /**
     * 行项目
     * 
     * @return 行项目列表
     */
    public List<ILineItem> getLineItems();

    /**
     * 数据流
     * 
     * @return LineItem 的流
     */
    public Stream<ILineItem> stream();

    /**
     * 
     * @param action
     */
    public void forEach(Consumer<? super ILineItem> action);

    /**
     * 获取行项目
     * 
     * @param b 是否强制刷新,false 读取缓存,true 读取数据库
     * @return 获取行项目
     */
    public default List<ILineItem> getLineItems(final boolean b) {
        if (b) {
            final var sql = FT(
                    "select b.id,b.name,b.price,b.money,a.quantity,a.amount "
                            + "from (select * from tbl$ where entity_id=$0) a inner join t_product b on a.item_id=b.id",
                    this.getId());
            final var dataApp = this.dataApp();
            final var erpApp = this.erpApp();
            final var lineItems = dataApp.rel2df_sql_f("t_contract", "t_product").apply(sql).rowsS()
                    .map(e -> erpApp.lineItemOf(erpApp.productOf(e), e.dbl("quantity"))).collect(Collectors.toList());
            this.setLineItems(lineItems);
            return lineItems;
        } // if

        return this.getLineItems();
    }

    /*
     * 订单总额
     * 
     * @return 获取总额
     */
    public default Double getTotal() {
        return this.stream().collect(Collectors.summarizingDouble(e -> e.getUnitPrice().getAmount() * e.getQuantity()))
                .getSum();
    }

   /**
    * 数据持久化
    * 
    * @return
    */
   public default IOrder<S> persist() {
       // 合同数据
       final var amount = this.getLineItems().stream().filter(e->e.getTotal()!=null)
           .collect(Collectors.summarizingDouble(e->e.getTotal().getAmount()))
           .getSum();
       final var rec = REC("partA", this.getPartA().getId(), "partB", this.getPartB().getId(), 
           "name", this.getName(), "path","D:/sliced/files/products/valuables/gold.jpg", 
           "amount",amount,"flag", this.getStatus().getId(), "create_time",this.getCreateTime());
       final var dtfmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
       
       final var dataApp = this.dataApp();
       dataApp.withTransaction(sess -> {
           if (this.getId() == null) { // 数据尚未持久化
               rec.set("name", FT("$0-$1",rec.str("name"),now().format(dtfmt)));// 合同名加入时间后缀
               final var sql = SQL.of("t_contract", rec).insert();
               //println(sql);
               final var entity_id = this.setId(sess.sql2execute2int(sql)); // 数据插入
               final var pattern = FT("insert into t_entity_item_rel"
                   + "(name,path,entity_id,item_id,quantity,amount,drcr,optional,description,flag,create_time) values "
                   + "${foreach e in entries ('t_contract/t_product','D:/sliced/files/products/valuables/gold.jpg',"
                   +    "e.entityId,e.itemId,e.quantity,e.amount,0,e.optional,e.description,0,'$0')}",LocalDateTime.now());
           
               final var entries = this.getLineItems().stream().map(e -> REC("entityId", entity_id, "itemId", e.getProduct().getId(), "quantity",
                   e.getQuantity(), "amount", e.getTotal().getAmount(), "optional", e.getUnitPrice().getAmount(),
                   "description", FT("$0[$1]", e.getProduct().getName(), e.getProduct().attr("money", "-"))) // REC
               ).collect(Collectors.toList());
               
               if (this.getLineItems() != null) {
                   sess.sqlexecute(nsql(pattern,REC("entries",entries)));
               }// if
              
           } else { // 数据已经持久化
               final var r = REC("id", this.getId()).derive(rec);
               final var sql = SQL.of("t_contract", r).update2();
               //println(sql);
               sess.sql2execute2int(sql); // 数据插入
           } // if
       }); // withTransaction
   
       return this;
   }
   
   /**
    * 归集器
    * 
    * @param <U>       归并结果
    * @param mapper    行项目映射器 lineitem->u
    * @param collector 归集器
    * @return U 类型的结果
    */
   public default <T, U> U collect(final Function<ILineItem, T> mapper, final Collector<T, ?, U> collector) {
       return this.stream().map(mapper).collect(collector);
   }

   /**
    * 归集器
    * 
    * @param <U>       归并结果
    * @param collector 归集器
    * @return U 类型的结果
    */
   public default <U> U collect(final Collector<ILineItem, ?, U> collector) {
       return this.collect(e -> e, collector);
   }
}
